package UIAutomator

import (
	"fmt"
	"github.com/antchfx/xmlquery"
	"github.com/tidwall/gjson"
	"io"
	"sonic-agent-plus/define/api"
	"sonic-agent-plus/define/common_error"
	"sonic-agent-plus/internal/element/UIAutomator/tool"
	"strings"
)

var (
	DEFAULT_REQUEST_TIMEOUT = 15000
	FIND_ELEMENT_INTERVAL   = 3000
	FIND_ELEMENT_RETRY      = 5
)

var _ api.IPageDriver = (*UIAutomator)(nil)

func NewUIAutomator(url string, timeout ...int) *UIAutomator {
	u := &UIAutomator{
		baseUrl: url,
	}
	if len(timeout) == 0 {
		u.timeout = DEFAULT_REQUEST_TIMEOUT
	} else {
		u.timeout = timeout[0]
	}
	return u
}

type UIAutomator struct {
	baseUrl string
	timeout int

	sessionId string
}

func (U *UIAutomator) Start() error {
	return U.newSession()
}

func (U *UIAutomator) Stop() error {
	return U.closeSession()
}

func (U *UIAutomator) DumpRootToXml() (*xmlquery.Node, error) {
	pageStr, err := U.pageSource()
	if err != nil {
		return nil, err
	}
	doc, err := xmlquery.Parse(strings.NewReader(pageStr))
	if err != nil {
		return nil, err
	}
	return doc, nil
}

func (U *UIAutomator) FindXmlNodeByXpath(xpath string) (*xmlquery.Node, error) {
	//TODO implement me
	panic("implement me")
}

func (U *UIAutomator) newSession() error {
	body := map[string]interface{}{
		"capabilities": map[string]interface{}{},
	}
	resp, err := tool.CreatePostRequest(U.baseUrl+"/session", body)
	if err != nil {
		return err
	}
	jsonData, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	msg := gjson.Parse(string(jsonData))
	if !msg.Get("err").Exists() {
		U.sessionId = msg.Get("value").Get("sessionId").String()
		return nil
	} else {
		return fmt.Errorf(msg.Get("err").String())
	}
}

func (U *UIAutomator) closeSession() error {
	if U.sessionId != "" {
		tool.CreateDeleteRequest(U.baseUrl + "/session/" + U.sessionId)
	}
	return nil
}

func (U *UIAutomator) pageSource() (string, error) {
	if U.sessionId != "" {
		resp, err := tool.CreateGetRequest(U.baseUrl + "/session/" + U.sessionId + "/source")

		if err != nil {
			return "", err
		}
		jsonData, err := io.ReadAll(resp.Body)
		if err != nil {
			return "", err
		}
		msg := gjson.Parse(string(jsonData))
		if !msg.Get("err").Exists() {
			return msg.Get("value").String(), nil
		} else {
			return "", fmt.Errorf(msg.Get("err").String())
		}
	} else {
		return "", common_error.UIANoSessionIDError
	}
}
